<?php
/**
 * 阿里云摄像头
 */

namespace App\Kuafu\Shop\Service\CameraLibrary;

use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Iot\Iot;
use App\Kuafu\Shop\Enum\CodeEnum;
use App\Kuafu\Shop\Model\CameraModel;
use App\Library\FeiShu\SendFs;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class AliYunCamera extends CameraBase implements CameraInterface
{
    /**
     * @var string
     */
    private string $host = 'linkvisual.cn-shanghai.aliyuncs.com';
    /**
     * 实例 iot
     *
     * @var string
     */
    private string $iotInstanceId = 'iot-060a0b6k';

    /**
     * @var string
     */
    private string $productKey;

    /**
     * @var string
     */
    private string $deviceName;

    /**
     * 获取请求设备,客流数据可能需要用第二套三元组
     *
     * @return array
     */
    private function getEquipmentInfo(): array
    {
        return [
            'productKey' => $this->productKey,
            'deviceName' => $this->deviceName
        ];
    }

    /**
     * 初始化
     *
     * @throws ClientException
     */
    public function init(): void
    {
        AlibabaCloud::accessKeyClient(config('camera.aliyun.aliyunCameraAccessId'),
            config('camera.aliyun.aliyunCameraAccessSecret'))
                    ->regionId('cn-shanghai')
                    ->asDefaultClient();

        if ($this->cameraModel->tripleType == 1) {
            $newCameraModel = CameraModel::query()
                                         ->where('shopId', $this->cameraModel->shopId)
                                         ->where('mac', $this->cameraModel->mac)
                                         ->where('tripleType', 2)
                                         ->first();

            $this->deviceName = $newCameraModel->deviceName;
            $this->productKey = $newCameraModel->productKey;
        } else {
            $this->deviceName = $this->cameraModel->deviceName;
            $this->productKey = $this->cameraModel->productKey;
        }
    }

    /**
     * 直播流
     *
     * @param string $scheme
     * @param array $streamType ['StreamType' => 0 | 1 (0 主码流 1辅码流)]
     * @return array|string[]
     */
    public function getLiveStreaming(string $scheme, int $clarity = CodeEnum::CLARITY_TYPE_FLUENCY): array
    {
        $scheme     = self::switchScheme($scheme);
        $streamType = self::switchClarity($clarity);
        $result     = $this->curl('QueryLiveStreaming', [
            'Scheme'           => $scheme,
            'PlayUnLimited'    => "true",
            'StreamType'       => $streamType,
            'UrlValidDuration' => "3600",
            'CacheDuration'    => 3000
        ]);
        try {
            $data = $result['Data'] ?? [];
            return [
                'url' => $data['Path'] ?? '',
            ];

        } catch (\Exception $exception) {
            $this->logErr(__FUNCTION__, $result, $exception);
            return [
                'url' => '',
            ];
        }
    }

    /**
     * 心跳
     *
     * @return array
     */
    public function heartBeat(): array
    {
        return [];
    }

    /**
     * 获取设备状态
     *
     * @param string $pk
     * @param string $dn
     * @return int
     * @throws ClientException
     * @throws ServerException
     */
    public function getDeviceStatus(string $pk = '', string $dn = ''): int
    {
        $request = Iot::v20180120()->getDeviceStatus();
        $result  = $request
            ->withIotInstanceId($this->iotInstanceId)
            ->withProductKey($pk ?: $this->productKey)
            ->withDeviceName($dn ?: $this->deviceName)
            ->request();

        try {
            $data = $result['Data'];
            if ($data['Status'] == 'ONLINE') {
                return 1;
            } else {
                return 0;
            }
        } catch (\Exception $exception) {
            $this->logErr(__FUNCTION__, $result->toArray(), $exception);
            return 0;
        }
    }


    public function curl(string $action = '', array $query = []): array
    {
        $orgQuery = [
            'IotInstanceId' => $this->iotInstanceId,
            'ProductKey'    => $this->getEquipmentInfo()['productKey'],
            'DeviceName'    => $this->getEquipmentInfo()['deviceName'],
        ];

        $query += $orgQuery;

        $result = AlibabaCloud::rpc()
                              ->product('Linkvisual')
                              ->version('2018-01-20')
                              ->action($action)
                              ->method('POST')
                              ->host($this->host)
                              ->options([
                                  'query' => $query,
                              ])
                              ->request();

        $result = $result->toArray();


        Log::info('AliYunCamera-curl:', [
            'action' => $action,
            'host'   => $this->host,
            'query'  => $query,
            'result' => json_encode($result, JSON_UNESCAPED_UNICODE),
        ]);
        return $result;
    }

    /**
     * 获取配置
     *
     * @return array
     */
    public function getConfig()
    {
        return [
            'accessKey'     => config('camera.aliyun.aliyunCameraAccessId'),
            'accessSecret'  => config('camera.aliyun.aliyunCameraAccessSecret'),
            'iotInstanceId' => $this->iotInstanceId
        ];
    }

    public function logErr(string $title, array $result, \Exception $exception, array $requestParam = []): void
    {
        SendFs::newRobot(SendFs::ROBOT_BUSINESS_WARING)
              ->setTitleContent('阿里云视频SDK请求报错:' . $title, json_encode([
                  'requestParam' => [
                          'productKey' => $this->productKey,
                          'deviceName' => $this->deviceName,
                      ] + $requestParam,
                  'returnData'   => $result ?? [],
                  'exception'    => $exception->getMessage()
              ]))->send();
    }

    /**
     * 本地录像视频
     *
     * @param int $startAt
     * @param int $endAt
     * @return array
     */
    public function localVideoList(int $startAt, int $endAt): array
    {
        $args = [
            'BeginTime' => $startAt,
            'EndTime'   => $endAt,
            'Type'      => 99,
            'QuerySize' => 100
        ];

        $request = Iot::v20180120()->invokeThingService();
        $result  = $request
            ->withIotInstanceId($this->iotInstanceId)
            ->withProductKey($this->productKey)
            ->withDeviceName($this->deviceName)
            ->withIdentifier("QueryRecordTimeList")
            ->withArgs(json_encode($args))
            ->request();

        try {
            $data       = $result['Data'];
            $dataResult = json_decode($data['Result'], 1);
            $returnData = [];
            foreach ($dataResult['TimeList'] as $list) {
                $returnData[] = [
                    'type'      => $list['Type'],
                    'endTime'   => $list['EndTime'],
                    'beginTime' => $list['BeginTime']
                ];
            }

        } catch (\Exception $exception) {
            $this->logErr(__FUNCTION__, $result->toArray(), $exception);
            $returnData = [];
        }

        foreach ($returnData as &$r) {
            if ($r['beginTime'] < $startAt) {
                $r['beginTime'] = $startAt;
            }

            if ($r['endTime'] > $endAt) {
                $r['endTime'] = $endAt;
            }
        }

        return $returnData;
    }


    /**
     * 批量获取设备状态
     *
     * @param array $cameraList
     * @return mixed
     */
    public function getDeviceStatusBatch(array $cameraList)
    {
        return Cache::remember('getDeviceStatusBatch:' . md5(json_encode($cameraList)), 300,
            function () use ($cameraList) {
                foreach ($cameraList as &$value) {
                    $value['status'] = self::getDeviceStatus($value['productKey'], $value['deviceName']);
                }
                return $cameraList;
            });
    }


    /**
     * 调用该接口，获取本地NVR设备或IPC设备存储卡中，指定录像时间范围的录像文件播放地址
     *
     * @param int $startAt
     * @param int $endAt
     * @param int $seekTime
     * @param string $scheme
     * @return array|string[]
     * @throws ClientException
     * @throws ServerException
     */
    public function backUrl(int $startAt, int $endAt, int $seekTime, string $scheme = 'flv'): array
    {
        $scheme = self::switchScheme($scheme);
        $result = $this->requestCamera('QueryDeviceVodUrlByTime', [
            'Scheme'           => $scheme,
            'SeekTime'         => $seekTime,
            'BeginTime'        => $startAt,
            'EndTime'          => $endAt,
            'PlayUnLimited'    => "true",
            'UrlValidDuration' => 3600,
            'ShouldEncrypt'    => false
        ]);
        try {
            $data = $result['Data'];

            return [
                'url' => $data['VodUrl'],
            ];

        } catch (\Exception $exception) {
            $this->logErr(__FUNCTION__, $result, $exception);
            return [
                'url' => '',
            ];
        }
    }


    /**
     * 阿里云 sdk curl 请求
     *
     * @param string $action
     * @param array $query
     * @return array
     * @throws ClientException
     * @throws ServerException
     */
    public function requestCamera(string $action, array $query = []): array
    {
        $orgQuery = [
            'IotInstanceId' => $this->iotInstanceId,
            'ProductKey'    => $this->productKey,
            'DeviceName'    => $this->deviceName,
        ];

        $query += $orgQuery;

        $result = AlibabaCloud::rpc()
                              ->product('Linkvisual')
                              ->version('2018-01-20')
                              ->action($action)
                              ->method('POST')
                              ->host($this->host)
                              ->options([
                                  'query' => $query,
                              ])
                              ->request();


        Log::info('AliYunCamera-requestCamera:', [
            'action' => $action,
            'host'   => $this->host,
            'query'  => $query,
            'result' => json_encode($result->toArray(), JSON_UNESCAPED_UNICODE),
        ]);
        return $result->toArray();
    }


    /**
     * 码流切换
     *
     * @param int $clarity
     * @return int
     */
    public function switchClarity(int $clarity = CodeEnum::CLARITY_TYPE_FLUENCY): int
    {
        switch ($clarity) {
            case CodeEnum::CLARITY_TYPE_FLUENCY:
                return 1; // 辅码流
            default:
                return 0; // 主码流
        }
    }

    /**
     * 阿里云摄像头-协议转换
     * @param string $scheme
     * @return string
     */
    public function switchScheme(string $scheme): string
    {
        return $scheme;
    }
}
